package org.budo.sso;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.budo.sso.config.BudoSsoCallback;
import org.budo.sso.config.BudoSsoConfig;
import org.budo.support.freemarker.FreemarkerUtil;
import org.budo.support.lang.util.ArrayUtil;
import org.budo.support.lang.util.MapUtil;
import org.budo.support.lang.util.NumberUtil;
import org.budo.support.lang.util.SystemUtil;
import org.budo.support.mvcs.Mvcs;
import org.budo.support.servlet.util.ResponseUtil;
import org.budo.support.spring.io.util.ResourceUtil;
import org.budo.support.spring.util.SpringUtil;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

/**
 * @author lmw
 */
@Slf4j
@Getter
@Setter
public abstract class AbstractBudoSsoFilter implements Filter {
    private static final String[] PRIMITIVE_PARAMETERS = new String[] { "app_key", "redirect_uri" };

    private BudoSsoConfig ssoConfig;

    private BudoSsoCallback ssoCallback;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("#22 init, this=" + this);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("#27 doFilter, this=" + this);
    }

    @Override
    public void destroy() {
        log.info("#31 destroy, this=" + this);
    }

    protected void handleSsoIndex(HttpServletRequest request, HttpServletResponse response) {
        log.info("#72 request=" + request + ", response=" + response + ", this=" + this);

        BudoSsoConfig ssoConfig = this.ssoConfig();

        String contextPath = request.getContextPath();
        Properties properties = SystemUtil.getProperties();
        Properties env = SystemUtil.getEnv();

        Map<String, Object> dataMap = MapUtil.stringObjectMap("contextPath", contextPath, //
                "ssoConfig", ssoConfig, //
                "properties", properties, //
                "env", env);

        InputStream inputStream = ResourceUtil.classPathResourceInputStream("sso.htm");
        FreemarkerUtil.freemarkerRender(inputStream, dataMap, ResponseUtil.getOutputStream(response)); // 渲染默认的 登录页
    }

    protected BudoSsoConfig ssoConfig() {
        if (null != this.getSsoConfig()) {
            return this.getSsoConfig();
        }

        BudoSsoConfig ssoConfig = SpringUtil.getBean(BudoSsoConfig.class);
        if (null != ssoConfig) {
            return ssoConfig;
        }

        throw new RuntimeException("#125 no ssoConfig, this=" + this);
    }

    protected BudoSsoCallback ssoCallback() {
        if (null != this.getSsoCallback()) {
            return this.getSsoCallback();
        }

        BudoSsoCallback ssoCallback = SpringUtil.getBean(BudoSsoCallback.class);
        if (null != ssoCallback) {
            return ssoCallback;
        }

        throw new RuntimeException("#112 no ssoCallback, this=" + this);
    }

    public static String _passThroughParameters(Map<String, String[]> parameterMap) {
        String passThroughParameters = "";
        for (Entry<String, String[]> entry : parameterMap.entrySet()) {
            String key = entry.getKey();

            if (ArrayUtil.valueInArray(key, PRIMITIVE_PARAMETERS)) { // 包含
                continue;
            }

            for (String value : entry.getValue()) {
                passThroughParameters += "&" + key + "=" + value;
            }
        }
        return passThroughParameters;
    }

    public String _buildRedirectUriPrefix(HttpServletRequest request) {
        log.info("#122 _buildRedirectUriPrefix, serverName=" + Mvcs.getServerName(request) + ", requestURI=" + Mvcs.getRequestURI(request) + ", headers=" + Mvcs.getRequestHeaderMap(request));

        String serverName = Mvcs.getServerName(request);
        Integer serverPort = Mvcs.getServerPort(request);

        String scheme = request.getScheme();
        String contextPath = request.getContextPath();

        String redirectUri = scheme + "://" + serverName;

        if (("http".equals(scheme) && NumberUtil.equals(80, serverPort)) || "https".equals(scheme) && NumberUtil.equals(443, serverPort)) {
            // 默认端口
        } else {
            redirectUri += ":" + serverPort; // 指定端口
        }

        redirectUri += contextPath;
        return redirectUri;
    }
}